#region Copyright (c) 2000-2002 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       XtraUtils Library                                           }
{                                                                   }
{       Copyright (c) 2000-2002 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2002 Developer Express Inc.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Collections;
namespace CUtil.Win32
{
	public interface IHookController {
		bool InternalPreFilterMessage(int Msg, IntPtr HWnd, IntPtr WParam, IntPtr LParam);
		bool InternalPostFilterMessage(int Msg, IntPtr HWnd, IntPtr WParam, IntPtr LParam);
	}
	public class HookManager {
		public ArrayList HookControllers;
		static HookManager defaultManager = new HookManager();
		public static HookManager DefaultManager { get { return defaultManager; } }
		public HookManager() {
			HookControllers = new ArrayList();
		}
		public void AddController(IHookController ctrl) {
			HookControllers.Add(ctrl);
			if(HookControllers.Count == 1) InstallHook();
		}
		public void RemoveController(IHookController ctrl) {
			HookControllers.Remove(ctrl);
			if(HookControllers.Count == 0) RemoveHook(false);
		}
		internal void InstallHook() {
			if(wndHookHandle != IntPtr.Zero) return;
			mouseHookProc = new Hook(MouseHook);
			wndHookProc = new Hook(WndHook);
            //wndHookHandle = SetWindowsHookEx(4, wndHookProc, 0, System.Threading.Thread.CurrentThread.ManagedThreadId);
            wndHookHandle = SetWindowsHookEx(4, wndHookProc, 0, System.Threading.Thread.CurrentThread.ManagedThreadId);
            mouseHookHandle = SetWindowsHookEx(7, mouseHookProc, 0, System.Threading.Thread.CurrentThread.ManagedThreadId);

            //wndHookHandle = SetWindowsHookEx(4, wndHookProc, 0, AppDomain.GetCurrentThreadId());
            //mouseHookHandle = SetWindowsHookEx(7, mouseHookProc, 0, AppDomain.GetCurrentThreadId());

			Application.ApplicationExit += new EventHandler(OnApplicationExit);

		}
		internal void RemoveHook(bool disposing) {
			if(wndHookHandle != IntPtr.Zero) {
				Application.ApplicationExit -= new EventHandler(OnApplicationExit);
				UnhookWindowsHookEx(wndHookHandle);
				wndHookHandle = IntPtr.Zero;
				wndHookProc = null;
				UnhookWindowsHookEx(mouseHookHandle);
				mouseHookHandle = IntPtr.Zero;
				mouseHookProc = null;
			}
		}
		private void OnApplicationExit(object sender, EventArgs e) {
			RemoveHook(true);
		}
		IntPtr wndHookHandle = IntPtr.Zero;
		IntPtr mouseHookHandle = IntPtr.Zero;
		Hook wndHookProc = null;
		Hook mouseHookProc = null;
		public delegate int Hook(int ncode, IntPtr wParam, IntPtr lParam);
		[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
			internal struct CWPSTRUCT { 
			public IntPtr lParam; 
			public IntPtr wParam; 
			public int    message; 
			public IntPtr    hwnd; 
		}
		[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
			internal struct POINT { 
			public int X;
			public int Y;
		}
		[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
			internal struct MOUSEHOOKSTRUCT { 
			public POINT	 Pt; 
			public IntPtr	 hwnd; 
			public uint		 wHitTestCode; 
			public IntPtr	 dwExtraInfo; 
		}
		bool inHook = false;
		protected int WndHook(int ncode, IntPtr wParam, IntPtr lParam) {
			CWPSTRUCT hookStr = (CWPSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(CWPSTRUCT));
			int res = 0;
			if(!inHook && lParam != IntPtr.Zero) {
				try {
					inHook = true;
					res = InternalPreFilterMessage(hookStr.message, hookStr.hwnd, hookStr.wParam, hookStr.lParam) ? 1 : 0;
				} finally {
					inHook = false;
				}
			} else return CallNextHookEx(wndHookHandle, ncode, wParam, lParam);
			res = CallNextHookEx(wndHookHandle, ncode, wParam, lParam); 
			return res;
		}
		bool inMouseHook = false;
		protected int MouseHook(int ncode, IntPtr wParam, IntPtr lParam) {
			int res = 0;
			bool allowFutureProcess = true;
			if(ncode == 0) {
				MOUSEHOOKSTRUCT hookStr = (MOUSEHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(MOUSEHOOKSTRUCT));
				if(!inMouseHook && lParam != IntPtr.Zero) {
					try {
						inMouseHook = true;
						allowFutureProcess = !InternalPreFilterMessage(wParam.ToInt32(), hookStr.hwnd, IntPtr.Zero, new IntPtr((hookStr.Pt.X << 16) | hookStr.Pt.Y));
					} finally {
						inMouseHook = false;
					}
				} else return CallNextHookEx(mouseHookHandle, ncode, wParam, lParam);
			}
			res = CallNextHookEx(mouseHookHandle, ncode, wParam, lParam); 
			if(!allowFutureProcess) res = -1;
			return res;
		}
		[System.Runtime.InteropServices.DllImport("USER32.dll")]
		protected static extern IntPtr SetWindowsHookEx(int idHook, Hook lpfn, int hMod,int dwThreadId);
		[System.Runtime.InteropServices.DllImport("USER32.dll")]
		protected static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam,  IntPtr lParam);
		[System.Runtime.InteropServices.DllImport("USER32.dll")]
		protected static extern bool UnhookWindowsHookEx(IntPtr hhk);
		internal bool InternalPreFilterMessage(int Msg, IntPtr HWnd, IntPtr WParam, IntPtr LParam) {
			bool result = false;
			for(int n = 0; n < HookControllers.Count; n ++) {
				IHookController ctrl = HookControllers[n] as IHookController;
				result |= ctrl.InternalPreFilterMessage(Msg, HWnd, WParam, LParam);
			}
			return result;
		}
	}
}
